home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Capture / PlayCapMoniker / PlayCapMoniker.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  11.5 KB  |  411 lines

  1. //------------------------------------------------------------------------------
  2. // File: PlayCapMoniker.cpp
  3. //
  4. // Desc: DirectShow sample code - a very basic application using Capture
  5. //       Devices.  It creates a window and uses the first available Capture
  6. //       Device to render and preview video capture data.
  7. //
  8. //       Instead of building the capture graph manually using the
  9. //       ICaptureGraphBuilder2 interface, this sample simply finds the moniker 
  10. //       of the first available capture device, finds its display name, and 
  11. //       uses RenderFile() to automatically build the graph.
  12. //
  13. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  14. //------------------------------------------------------------------------------
  15.  
  16.  
  17. #include <atlbase.h>
  18. #include <windows.h>
  19. #include <streams.h>
  20. #include <stdio.h>
  21. #include <comdef.h>
  22.  
  23. #include "PlayCapMoniker.h"
  24.  
  25. // An application can advertise the existence of its filter graph
  26. // by registering the graph with a global Running Object Table (ROT).
  27. // The GraphEdit application can detect and remotely view the running
  28. // filter graph, allowing you to 'spy' on the graph with GraphEdit.
  29. //
  30. // To enable registration in this sample, define REGISTER_FILTERGRAPH.
  31. //
  32. #define REGISTER_FILTERGRAPH
  33.  
  34. //
  35. // Global data
  36. //
  37. HWND ghApp=0;
  38. DWORD g_dwGraphRegister=0;
  39.  
  40. IVideoWindow  * g_pVW = NULL;
  41. IMediaControl * g_pMC = NULL;
  42. IMediaEventEx * g_pME = NULL;
  43. IGraphBuilder * g_pGraph = NULL;
  44.  
  45.  
  46. HRESULT CaptureVideoByMoniker()
  47. {
  48.     HRESULT hr;
  49.     IMoniker *pMoniker =NULL;
  50.     USES_CONVERSION;
  51.  
  52.     // Get DirectShow interfaces
  53.     hr = GetInterfaces();
  54.     if (FAILED(hr))
  55.     {
  56.         Msg(TEXT("Failed to get video interfaces!  hr=0x%x"), hr);
  57.         return hr;
  58.     }
  59.  
  60.     // Use the system device enumerator and class enumerator to find
  61.     // a moniker that representa a video capture/preview device, 
  62.     // such as a desktop USB video camera.
  63.     hr = FindCaptureDeviceMoniker(&pMoniker);
  64.     if (FAILED(hr))
  65.     {
  66.         // FindCaptureDeviceMoniker will display an error message
  67.         return hr;
  68.     }
  69.  
  70.     // Get the display name of the moniker
  71.     LPOLESTR strName=0;
  72.     hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
  73.     pMoniker->Release();
  74.  
  75.     if (FAILED(hr))
  76.     {
  77.         Msg(TEXT("Couldn't get moniker's display name!  hr=0x%x"), hr);
  78.         return hr;
  79.     }
  80.  
  81.     // We can call RenderFile on the moniker's name to build the graph.
  82.     // This saves the trouble of building the capture graph manually.
  83.     hr = g_pGraph->RenderFile(strName, NULL);
  84.     if (FAILED(hr))
  85.     {
  86.         Msg(TEXT("Couldn't render the capture graph!  hr=0x%x\r\n\r\n") 
  87.             TEXT("This sample requires a video capture device, such as a USB WebCam,\r\n")
  88.             TEXT("to be installed and working properly.  The sample will now close."), hr);
  89.         return hr;
  90.     }            
  91.  
  92. #ifdef DEBUG
  93.     // Get a human-readable string for evaluation during debugging
  94.     TCHAR szMonikerName[256]={0};
  95.     _tcscpy(szMonikerName, W2T(strName));
  96.     //  Msg(TEXT("Moniker: %s\r\n"), szMonikerName);
  97. #endif
  98.  
  99.     // Set the video window to be a child of the main window
  100.     hr = g_pVW->put_Owner((OAHWND)ghApp);
  101.     if (FAILED(hr))
  102.     {
  103.         Msg(TEXT("Couldn't set video window owner!  hr=0x%x"), hr);
  104.         return hr;
  105.     }            
  106.  
  107.     // Add our graph to the running object table, which will allow
  108.     // the GraphEdit application to "spy" on our graph
  109. #ifdef REGISTER_FILTERGRAPH
  110.     hr = AddGraphToRot(g_pGraph, &g_dwGraphRegister);
  111.     if (FAILED(hr))
  112.     {
  113.         Msg(TEXT("Failed to register filter graph with ROT!  hr=0x%x"), hr);
  114.         g_dwGraphRegister = 0;
  115.     }
  116. #endif
  117.  
  118.     // Start previewing video data
  119.     hr = g_pMC->Run();
  120.     if (FAILED(hr))
  121.     {
  122.         Msg(TEXT("Couldn't run the graph!  hr=0x%x"), hr);
  123.         return hr;
  124.     }
  125.  
  126.     return hr;   
  127. }
  128.  
  129.  
  130. HRESULT FindCaptureDeviceMoniker(IMoniker **ppMoniker)
  131. {
  132.     HRESULT hr;
  133.     ULONG cFetched;
  134.    
  135.     // Create the system device enumerator
  136.     CComPtr <ICreateDevEnum> pDevEnum =NULL;
  137.  
  138.     hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
  139.         IID_ICreateDevEnum, (void ** ) &pDevEnum);
  140.     if (FAILED(hr))
  141.     {
  142.         Msg(TEXT("Couldn't create system enumerator!  hr=0x%x"), hr);
  143.         return hr;
  144.     }
  145.  
  146.     // Create an enumerator for the video capture devices
  147.     CComPtr <IEnumMoniker> pClassEnum = NULL;
  148.  
  149.     hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
  150.     if (FAILED(hr))
  151.     {
  152.         Msg(TEXT("Couldn't create class enumerator!  hr=0x%x"), hr);
  153.         return hr;
  154.     }
  155.  
  156.     // If there are no enumerators for the requested type, then 
  157.     // CreateClassEnumerator will succeed, but pClassEnum will be NULL.
  158.     if (pClassEnum == NULL)
  159.     {
  160.         MessageBox(ghApp,TEXT("No video capture device was detected.\r\n\r\n")
  161.                    TEXT("This sample requires a video capture device, such as a USB WebCam,\r\n")
  162.                    TEXT("to be installed and working properly.  The sample will now close."),
  163.                    TEXT("No Video Capture Hardware"), MB_OK | MB_ICONINFORMATION);
  164.         return E_FAIL;
  165.     }
  166.  
  167.     // Use the first video capture device on the device list.
  168.     // Note that if the Next() call succeeds but there are no monikers,
  169.     // it will return S_FALSE (which is not a failure).  Therefore, we
  170.     // check that the return code is S_OK instead of using SUCCEEDED() macro.
  171.     if (S_OK == (pClassEnum->Next (1, ppMoniker, &cFetched)))
  172.     {
  173.         return S_OK;
  174.     }
  175.     else
  176.     {
  177.         Msg(TEXT("Unable to access video capture device!"));   
  178.         return E_FAIL;
  179.     }
  180.  
  181.     return hr;
  182. }
  183.  
  184.  
  185. HRESULT GetInterfaces(void)
  186. {
  187.     HRESULT hr;
  188.  
  189.     // Create the filter graph
  190.     hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC,
  191.         IID_IGraphBuilder, (void **) &g_pGraph);
  192.     if (FAILED(hr))
  193.         return hr;
  194.  
  195.     // Obtain interfaces for media control and Video Window
  196.     hr = g_pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &g_pMC);
  197.     if (FAILED(hr))
  198.         return hr;
  199.  
  200.     hr = g_pGraph->QueryInterface(IID_IVideoWindow, (LPVOID *) &g_pVW);
  201.     if (FAILED(hr))
  202.         return hr;
  203.  
  204.     hr = g_pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *) &g_pME);
  205.     if (FAILED(hr))
  206.         return hr;
  207.  
  208.     // Set the window handle used to process graph events
  209.     hr = g_pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);
  210.  
  211.     return hr;
  212. }
  213.  
  214.  
  215. void CloseInterfaces(void)
  216. {
  217.     // Stop previewing data
  218.     if (g_pMC)
  219.         g_pMC->Stop();
  220.  
  221.     // Stop receiving events
  222.     if (g_pME)
  223.         g_pME->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0);
  224.  
  225.     // Relinquish ownership (IMPORTANT!) of the video window.
  226.     // Failing to call put_Owner can lead to assert failures within
  227.     // the video renderer, as it still assumes that it has a valid
  228.     // parent window.
  229.     if(g_pVW)
  230.     {
  231.         g_pVW->put_Visible(OAFALSE);
  232.         g_pVW->put_Owner(NULL);
  233.     }
  234.  
  235. #ifdef REGISTER_FILTERGRAPH
  236.     // Remove filter graph from the running object table   
  237.     if (g_dwGraphRegister)
  238.         RemoveGraphFromRot(g_dwGraphRegister);
  239. #endif
  240.  
  241.     // Release DirectShow interfaces
  242.     SAFE_RELEASE(g_pMC);
  243.     SAFE_RELEASE(g_pME);
  244.     SAFE_RELEASE(g_pVW);
  245.     SAFE_RELEASE(g_pGraph);
  246. }
  247.  
  248.  
  249. #ifdef REGISTER_FILTERGRAPH
  250.  
  251. HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) 
  252. {
  253.     IMoniker * pMoniker;
  254.     IRunningObjectTable *pROT;
  255.     WCHAR wsz[128];
  256.     HRESULT hr;
  257.  
  258.     if (FAILED(GetRunningObjectTable(0, &pROT))) {
  259.         return E_FAIL;
  260.     }
  261.  
  262.     wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, 
  263.               GetCurrentProcessId());
  264.  
  265.     hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  266.     if (SUCCEEDED(hr)) {
  267.         hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
  268.         pMoniker->Release();
  269.     }
  270.     pROT->Release();
  271.     return hr;
  272. }
  273.  
  274. void RemoveGraphFromRot(DWORD pdwRegister)
  275. {
  276.     IRunningObjectTable *pROT;
  277.  
  278.     if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
  279.         pROT->Revoke(pdwRegister);
  280.         pROT->Release();
  281.     }
  282. }
  283.  
  284. #endif
  285.  
  286.  
  287. void Msg(TCHAR *szFormat, ...)
  288. {
  289.     TCHAR szBuffer[512];
  290.  
  291.     va_list pArgs;
  292.     va_start(pArgs, szFormat);
  293.     _vstprintf(szBuffer, szFormat, pArgs);
  294.     va_end(pArgs);
  295.  
  296.     MessageBox(NULL, szBuffer, TEXT("PlayCapMoniker Message"), MB_OK | MB_ICONERROR);
  297. }
  298.  
  299.  
  300. HRESULT HandleGraphEvent(void)
  301. {
  302.     LONG evCode, evParam1, evParam2;
  303.     HRESULT hr=S_OK;
  304.  
  305.     // Process all queued events
  306.     while(SUCCEEDED(g_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
  307.                     (LONG_PTR *) &evParam2, 0)))
  308.     {
  309.         // Free event parameters to prevent memory leaks
  310.         hr = g_pME->FreeEventParams(evCode, evParam1, evParam2);
  311.  
  312.         switch (evCode)
  313.         {
  314.             // When the user closes the capture window, close the app.
  315.             case EC_COMPLETE:
  316.             case EC_DEVICE_LOST:
  317.             case EC_ERRORABORT:
  318.             case EC_USERABORT:
  319.                 PostMessage(ghApp, WM_CLOSE, 0, 0);
  320.                 break;
  321.  
  322.             default:
  323.                 break;
  324.         }
  325.     }
  326.  
  327.     return hr;
  328. }
  329.  
  330.  
  331. LRESULT CALLBACK WndMainProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  332. {
  333.     switch (message)
  334.     {
  335.         case WM_GRAPHNOTIFY:    // Process events from the filter graph
  336.             HandleGraphEvent();
  337.             break;
  338.  
  339.         case WM_CLOSE:            
  340.             CloseInterfaces();  // Stop capturing and release interfaces
  341.             break;
  342.  
  343.         case WM_DESTROY:
  344.             PostQuitMessage(0);
  345.             return 0;
  346.     }
  347.     return DefWindowProc (hwnd , message, wParam, lParam);
  348. }
  349.  
  350.  
  351. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hInstP, LPSTR lpCmdLine, int nCmdShow)
  352. {
  353.     MSG msg={0};
  354.     WNDCLASS wc;
  355.     HRESULT hr;
  356.  
  357.     // Initialize COM
  358.     if(FAILED(CoInitialize(NULL)))
  359.     {
  360.         Msg(TEXT("CoInitialize Failed!\r\n"));   
  361.         exit(1);
  362.     } 
  363.  
  364.     // Register the window class
  365.     ZeroMemory(&wc, sizeof wc);
  366.     wc.lpfnWndProc   = WndMainProc;
  367.     wc.hInstance     = hInstance;
  368.     wc.lpszClassName = CLASSNAME;
  369.     wc.lpszMenuName  = NULL;
  370.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  371.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  372.     wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_VIDPREVIEW));
  373.     if(!RegisterClass(&wc))
  374.     {
  375.         Msg(TEXT("RegisterClass Failed! Error=0x%x\r\n"), GetLastError());
  376.         CoUninitialize();
  377.         exit(1);
  378.     }
  379.  
  380.     // Create the main window.  The WS_CLIPCHILDREN style is required.
  381.     // Since we will render a moniker to begin capturing video, the capture 
  382.     // graph will create its own window, so this main window will be hidden.
  383.     ghApp = CreateWindow(CLASSNAME, APPLICATIONNAME,
  384.                     WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_CLIPCHILDREN,
  385.                     CW_USEDEFAULT, CW_USEDEFAULT,
  386.                     DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT,
  387.                     0, 0, hInstance, 0);
  388.     if(ghApp)
  389.     {
  390.         // Create DirectShow graph and start capturing video
  391.         hr = CaptureVideoByMoniker();
  392.         if (FAILED (hr))
  393.         {
  394.             CloseInterfaces();
  395.             DestroyWindow(ghApp);
  396.         }
  397.  
  398.         // Main message loop
  399.         while(GetMessage(&msg,NULL,0,0))
  400.         {
  401.             TranslateMessage(&msg);
  402.             DispatchMessage(&msg);
  403.         }
  404.     }
  405.  
  406.     // Release COM
  407.     CoUninitialize();
  408.  
  409.     return ((int) msg.wParam);
  410. }
  411.